/**
 * Copyright (C), 2015-2019, XXX有限公司
 * FileName: ZHApplicationContext
 * Author:   zhouheng
 * Date:     2019/5/19 20:36
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.zhouh.springmvc.com.zhouh.mvc.framework.context;

import com.zhouh.springmvc.com.zhouh.mvc.framework.annotation.ZHAutowired;
import com.zhouh.springmvc.com.zhouh.mvc.framework.annotation.ZHController;
import com.zhouh.springmvc.com.zhouh.mvc.framework.annotation.ZHService;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhouheng
 * @create 2019/5/19
 * @since 1.0.0
 */
public class ZHApplicationContext {
    Map<String,Object> instanceMapping = new HashMap<>();
    private Properties config = new Properties();
    List<String> classCache = new ArrayList<String>();

    /**
     * @description:
     * @date: 2019/5/19 21:26
     * @author:zhouheng
     */
    public ZHApplicationContext(String location) {
        InputStream is = null;

        try {
            // 1.定位
            is = this.getClass().getClassLoader().getResourceAsStream(location);
            // 2.加载
            config.load(is);
            // 3.注册，将class类交由ZhSpring容器管理
            String packageName = config.getProperty("scanPackage");
            doRegister(packageName);
            //4、实例化需要ioc的对象(就是加了@Service，@Controller)
            doCreateBean(classCache);
            //5、注入
            populate();


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @description: 依赖注入
     * @date: 2019/5/19 22:19
     * @author:zhouheng
     */
    private void populate() {
        if (instanceMapping != null && instanceMapping.size() > 0){
            for (Map.Entry<String, Object> entry : instanceMapping.entrySet()){
                Field[] fields = entry.getValue().getClass().getDeclaredFields();
                for (Field field : fields){
                    if (field.isAnnotationPresent(ZHAutowired.class)){
                        ZHAutowired zhAutowired = field.getAnnotation(ZHAutowired.class);
                        String id = zhAutowired.value().trim();
                        if (StringUtils.equals("", id)){
                            // 默认按类型
                            id = field.getType().getName();
                        }
                        field.setAccessible(true); //把私有变量开放访问权限

                        try {
                            field.set(entry.getValue(), instanceMapping.get(id));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }else {
                        continue;
                    }
                }

            }
        }
    }

    /**
     * @description: 创建bean @Cotroller @Service
     * @date: 2019/5/19 21:26
     * @author:zhouheng
     */
    private void doCreateBean(List<String> classCache) {
        if (classCache != null && classCache.size() > 0){
            try {
                for (String classFullName : classCache){
                    Class clazz = Class.forName(classFullName);

                    if (clazz.isAnnotationPresent(ZHController.class)){
                        //名字起啥？默认就是类名首字母小写
                        String beanName = lowerFirstChar(clazz.getSimpleName());
                        instanceMapping.put(beanName, clazz.newInstance());
                    }else if (clazz.isAnnotationPresent(ZHService.class)){
                        ZHService zhService = (ZHService) clazz.getAnnotation(ZHService.class);
                        if (!StringUtils.equals("",zhService.value())){
                            instanceMapping.put(zhService.value(),clazz.newInstance());
                            continue;
                        }

                        // 当前注解在接口上？还是在实现类上
                        Class<?>[] interfaces = clazz.getInterfaces();
                        //如果这个类实现了接口，就用接口的类型作为id
                        for (Class<?> i : interfaces) {
                            instanceMapping.put(i.getName(), clazz.newInstance());
                        }
                    }else {
                        continue;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @description: 首字母大小写转换
     * @date: 2019/5/19 21:45
     * @author:zhouheng
     */
    private String lowerFirstChar(String simpleName) {
        return StringUtils.capitalize(simpleName);
    }

    /**
     * @description: 将包扫描到得所有class 注册到spring容器
     * @date: 2019/5/19 21:26
     * @author:zhouheng
     */
    private void doRegister(String packageName) {
        if (StringUtils.isNotBlank(packageName)){
            URL url = this.getClass().getClassLoader().getResource("/"+packageName.replaceAll("\\.","/")+"/");
            File dir = new File(url.getFile());
            for (File file : dir.listFiles()){
                if (file.isDirectory()){
                    doRegister(packageName + "." + file.getName());
                }else {
                    classCache.add(packageName + "." + file.getName().replace(".class", "").trim());
                }
            }
        }
    }

    /**
     * @description: 获取ioc容器
     * @date: 2019/5/20 21:36
     * @author:zhouheng
     */
    public Map<String,Object> getAll(){
        return instanceMapping;
    }

    public Properties getConfig() {
        return config;
    }
}